/** -*- c -*-
 *  Copyright (C) 2011
 *  University of Rochester Department of Computer Science
 *    and
 *  Lehigh University Department of Computer Science and Engineering
 *
 * License: Modified BSD
 *          Please see the file LICENSE.RSTM for licensing information
 */

#ifndef RSTM_LIBITM_DTFN
# define RSTM_LIBITM_DTFN(S, CC, R, ...)
# define _RSTM_LIBITM_UNDEF_DTFN
#endif

/// ---------------------------------------------------------------------------
/// This file is defined for multiple inclusion, and describes the ITM Data
/// Transfer Functions functions using a declarative macro style. We can use
/// this to generate ABI calls as necessary.
/// ---------------------------------------------------------------------------
///
/// Available macros
///
/// macro: RSTM_LIBITM_DTFN(symbol, calling_conventions, return_type,
///                             ... /* param_types */)
/// -- Defined for all functions.
///
/// macro: RSTM_LIBITM_READ(S, CC, TYPE)
/// -- Defined for all of the ITM_R* variants
///
/// macro: RSTM_LIBITM_READ_R(S, CC, TYPE)
/// -- Defined for all of the ITM_R variants
///
/// macro: RSTM_LIBITM_READ_RaR(S, CC, TYPE)
/// -- Defined for all of the ITM_RaR variants
///
/// macro: RSTM_LIBITM_READ_RaW(S, CC, TYPE)
/// -- Defined for all of the ITM_RaW variants
///
/// macro: RSTM_LIBITM_READ_RfW(S, CC, TYPE)
/// -- Defined for all of the ITM_RfW variants
///
/// macro: RSTM_LIBITM_WRITE(S, CC, TYPE)
/// -- Defined for all of the ITM_W* variants
///
/// macro: RSTM_LIBITM_WRITE_W(S, CC, TYPE)
/// -- Defined for all of the ITM_W variants
///
/// macro: RSTM_LIBITM_WRITE_WaR(S, CC, TYPE)
/// -- Defined for all of the ITM_WaR variants
///
/// macro: RSTM_LIBITM_WRITE_WaW(S, CC, TYPE)
/// -- Defined for all of the ITM_WaW variants
///
/// macro: RSTM_LIBITM_LOG(S, CC, TYPE)
/// -- Defined for all of the ITM_L variants, except for
///    'void _ITM_LB (const void *, size_t);'
///
/// macro: RSTM_LIBITM_MEMCPY(S, RTx, WTx)
/// -- Defined for all of the ITM_memcpy variants, RTx and WTx are bools
///    indicating if the read and write accesses should be transactional
///
/// macro: RSTM_LIBITM_MEMMOVE(S, RTx, WTx)
/// -- Defined for all of the ITM_memmove variants, RTx and WTx are bools
///    indicating if the read and write accesses should be transactional
///
/// macro: RSTM_LIBITM_MEMSET(S)
/// -- Defined for all of the ITM_memset variants
/// ---------------------------------------------------------------------------

#ifdef __cplusplus
extern "C" {
#endif

    // ------------------------------------------------------------------------
    //  This section generates all of the Data Transfer functions.
    // ------------------------------------------------------------------------

    // Macros that will expand a macro with a type and a suffix, for all of the
    // Data Transfer Types defined in the ABI.
#define _RSTM_LIBITM_1B(macro) macro(uint8_t, U1)
#define _RSTM_LIBITM_2B(macro) macro(uint16_t, U2)
#define _RSTM_LIBITM_4B(macro) macro(uint32_t, U4)
#define _RSTM_LIBITM_8B(macro) macro(uint64_t, U8)
#define _RSTM_LIBITM_F(macro) macro(float, F)
#define _RSTM_LIBITM_D(macro) macro(double, D)
#define _RSTM_LIBITM_LD(macro) macro(long double, E)
#define _RSTM_LIBITM_CF(macro) macro(float _Complex, CF)
#define _RSTM_LIBITM_CD(macro) macro(double _Complex, CD)
#define _RSTM_LIBITM_CLD(macro) macro(long double _Complex, CE)

    // TODO: make the immintrin.h inclusion configure-based.
#if defined(__x86_64__) || defined(__i386__)
# include <immintrin.h>
# if defined(__AVX__)
#  define _RSTM_LIBITM_M256(macro) macro(__256, M256)
#  define _RSTM_LIBITM_M128(macro) macro(__m128, M128)
#  define _RSTM_LIBITM_M64(macro) macro(__m64, M64)
# elif defined(__SSE__)
#  define _RSTM_LIBITM_M256(macro)
#  define _RSTM_LIBITM_M128(macro) macro(__m128, M128)
#  define _RSTM_LIBITM_M64(macro) macro(__m64, M64)
# elif defined(__MMX__)
#  define _RSTM_LIBITM_M256(macro)
#  define _RSTM_LIBITM_M128(macro)
#  define _RSTM_LIBITM_M64(macro) macro(__m64, M64)
# else
#  define _RSTM_LIBITM_M256(macro)
#  define _RSTM_LIBITM_M128(macro)
#  define _RSTM_LIBITM_M128(macro)
# endif
#endif

    // This internal macro will expand the passed, 2-parameter macro for each
    // ABI type.
#define _RSTM_LIBITM_FORALL_TYPES(macro)                        \
    _RSTM_LIBITM_1B(macro)                                      \
    _RSTM_LIBITM_2B(macro)                                  \
    _RSTM_LIBITM_4B(macro)                                  \
    _RSTM_LIBITM_8B(macro)                                  \
    _RSTM_LIBITM_F(macro)                                   \
    _RSTM_LIBITM_D(macro)                                   \
    _RSTM_LIBITM_LD(macro)                                  \
    _RSTM_LIBITM_CF(macro)                                  \
    _RSTM_LIBITM_CD(macro)                                  \
    _RSTM_LIBITM_CLD(macro)                                 \
    _RSTM_LIBITM_M64(macro)                                 \
    _RSTM_LIBITM_M128(macro)                                \
    _RSTM_LIBITM_M256(macro)

    // This internal macro generates the external macros for a read barrier.
#define _RSTM_LIBITM_GENERATE_READ(type, suffix, T)                     \
    RSTM_LIBITM_DTFN(_ITM_##suffix##T,                                  \
                         ITM_REGPARM,                          \
                         type,                                          \
                         type *)                                  \
    RSTM_LIBITM_READ(_ITM_##suffix##T, ITM_REGPARM, type)      \
    RSTM_LIBITM_READ_##suffix(_ITM_##suffix##T, ITM_REGPARM, type)

    // This internal macro generates the external macros for a write barrier.
#define _RSTM_LIBITM_GENERATE_WRITE(type, suffix, T)                    \
    RSTM_LIBITM_DTFN(_ITM_##suffix##T,                                  \
                         ITM_REGPARM,                          \
                         void,                                          \
                         type *, type)                                  \
    RSTM_LIBITM_WRITE(_ITM_##suffix##T, ITM_REGPARM, type)     \
    RSTM_LIBITM_WRITE_##suffix(_ITM_##suffix##T, ITM_REGPARM, type)

    // This internal macro generates the external macros for the a log barrier.
#define _RSTM_LIBITM_GENERATE_LOG(type, T)                  \
    RSTM_LIBITM_DTFN(_ITM_L##T,                             \
                         ITM_REGPARM,              \
                         void,                              \
                         type*)                             \
    RSTM_LIBITM_LOG(_ITM_L##T, ITM_REGPARM, type)

    // This internal macro generates the 4 kinds of read barriers for a type.
#define _RSTM_LIBITM_GENALL_READS(type, T)           \
    _RSTM_LIBITM_GENERATE_READ(type, R, T)           \
    _RSTM_LIBITM_GENERATE_READ(type, RaR, T)         \
    _RSTM_LIBITM_GENERATE_READ(type, RaW, T)         \
    _RSTM_LIBITM_GENERATE_READ(type, RfW, T)

    // This internal macro generates the 3 kinds of write barriers for a type.
#define _RSTM_LIBITM_GENALL_WRITES(type, T)         \
    _RSTM_LIBITM_GENERATE_WRITE(type, W, T)         \
    _RSTM_LIBITM_GENERATE_WRITE(type, WaR, T)       \
    _RSTM_LIBITM_GENERATE_WRITE(type, WaW, T)


    // ------------------------------------------------------------------------
    //  These are all of the macros that are avaiable externally. We need to
    //  define defaults here if the includer isn't trying to use them.
    // ------------------------------------------------------------------------
#ifndef RSTM_LIBITM_READ
# define RSTM_LIBITM_READ(S, CC, TYPE)
# define _RSTM_LIBITM_UNDEF_READ 1
#endif

#ifndef RSTM_LIBITM_READ_R
# define RSTM_LIBITM_READ_R(S, CC, TYPE)
# define _RSTM_LIBITM_UNDEF_READ_R 1
#endif

#ifndef RSTM_LIBITM_READ_RaR
# define RSTM_LIBITM_READ_RaR(S, CC, TYPE)
# define _RSTM_LIBITM_UNDEF_READ_RaR 1
#endif

#ifndef RSTM_LIBITM_READ_RaW
# define RSTM_LIBITM_READ_RaW(S, CC, TYPE)
# define _RSTM_LIBITM_UNDEF_READ_RaW 1
#endif

#ifndef RSTM_LIBITM_READ_RfW
# define RSTM_LIBITM_READ_RfW(S, CC, TYPE)
# define _RSTM_LIBITM_UNDEF_READ_RfW 1
#endif

#ifndef RSTM_LIBITM_WRITE
# define RSTM_LIBITM_WRITE(S, CC, TYPE)
# define _RSTM_LIBITM_UNDEF_WRITE 1
#endif

#ifndef RSTM_LIBITM_WRITE_W
# define RSTM_LIBITM_WRITE_W(S, CC, TYPE)
# define _RSTM_LIBITM_UNDEF_WRITE_W 1
#endif

#ifndef RSTM_LIBITM_WRITE_WaR
# define RSTM_LIBITM_WRITE_WaR(S, CC, TYPE)
# define _RSTM_LIBITM_UNDEF_WRITE_WaR 1
#endif

#ifndef RSTM_LIBITM_WRITE_WaW
# define RSTM_LIBITM_WRITE_WaW(S, CC, TYPE)
# define _RSTM_LIBITM_UNDEF_WRITE_WaW 1
#endif

#ifndef RSTM_LIBITM_LOG
# define RSTM_LIBITM_LOG(S, CC, TYPE)
# define _RSTM_LIBITM_UNDEF_LOG 1
#endif

    // ------------------------------------------------------------------------
    //  These generates all of the
    //  - RSTM_LIBITM_DTFN,
    //  - RSTM_LIBITM_READ,
    //  - RSTM_LIBITM_READ_R,
    //  - RSTM_LIBITM_READ_RaR,
    //  - RSTM_LIBITM_READ_RaW,
    //  - RSTM_LIBITM_READ_RfW,
    //  - RSTM_LIBITM_WRITE,
    //  - RSTM_LIBITM_WRITE_W,
    //  - RSTM_LIBITM_WRITE_WaR,
    //  - RSTM_LIBITM_WRITE_WaW
    //  macros that are visible externally.
    // ------------------------------------------------------------------------
    _RSTM_LIBITM_FORALL_TYPES(_RSTM_LIBITM_GENALL_READS)
    _RSTM_LIBITM_FORALL_TYPES(_RSTM_LIBITM_GENALL_WRITES)
    _RSTM_LIBITM_FORALL_TYPES(_RSTM_LIBITM_GENERATE_LOG)

    //  One funny log function that doesn't match the standard ABI
    RSTM_LIBITM_DTFN(_ITM_LB,
                     ITM_REGPARM,
                     void,
                     const void*, size_t)

    // Undef RSTM_LIBITM_READ if we defined it locally.
#ifdef _RSTM_LIBITM_UNDEF_READ
# undef _RSTM_LIBITM_UNDEF_READ
# undef RSTM_LIBITM_READ
#endif

    // Undef RSTM_LIBITM_READ_R if we defined it locally.
#ifdef _RSTM_LIBITM_UNDEF_READ_R
# undef _RSTM_LIBITM_UNDEF_READ_R
# undef RSTM_LIBITM_READ_R
#endif

    // Undef RSTM_LIBITM_READ_RaR if we defined it locally.
#ifdef _RSTM_LIBITM_UNDEF_READ_RaR
# undef _RSTM_LIBITM_UNDEF_READ_RaR
# undef RSTM_LIBITM_READ_RaR
#endif

    // Undef RSTM_LIBITM_READ_RaW if we defined it locally.
#ifdef _RSTM_LIBITM_UNDEF_READ_RaW
# undef _RSTM_LIBITM_UNDEF_READ_RaW
# undef RSTM_LIBITM_READ_RaW
#endif

    // Undef RSTM_LIBITM_READ_RfW if we defined it locally.
#ifdef _RSTM_LIBITM_UNDEF_READ_RfW
# undef _RSTM_LIBITM_UNDEF_READ_RfW
# undef RSTM_LIBITM_READ_RfW
#endif

    // Undef RSTM_LIBITM_WRITE if we defined it locally.
#ifdef _RSTM_LIBITM_UNDEF_WRITE
# undef _RSTM_LIBITM_UNDEF_WRITE
# undef RSTM_LIBITM_WRITE
#endif

    // Undef RSTM_LIBITM_WRITE_W if we defined it locally.
#ifdef _RSTM_LIBITM_UNDEF_WRITE_W
# undef _RSTM_LIBITM_UNDEF_WRITE_W
# undef RSTM_LIBITM_WRITE_W
#endif

    // Undef RSTM_LIBITM_WRITE_WaR if we defined it locally.
#ifdef _RSTM_LIBITM_UNDEF_WRITE_WaR
# undef _RSTM_LIBITM_UNDEF_WRITE_WaR
# undef RSTM_LIBITM_WRITE_WaR
#endif

    // Undef RSTM_LIBITM_WRITE_WaW if we defined it locally.
#ifdef _RSTM_LIBITM_UNDEF_WRITE_WaW
# undef _RSTM_LIBITM_UNDEF_WRITE_WaW
# undef RSTM_LIBITM_WRITE_WaW
#endif

    // Undef RSTM_LIBITM_LOG if we defined it locally.
#ifdef _RSTM_LIBITM_UNDEF_LOG
# undef _RSTM_LIBITM_UNDEF_LOG
# undef RSTM_LIBITM_LOG
#endif

    // Undef the basic READ/WRITE expansions
#undef _RSTM_LIBITM_GENERATE_READ
#undef _RSTM_LIBITM_GENERATE_READ
#undef _RSTM_LIBITM_GENERATE_LOG
#undef _RSTM_LIBITM_GENALL_READS
#undef _RSTM_LIBITM_GENALL_WRITES
#undef _RSTM_LIBITM_FORALL_TYPES
#undef _RSTM_LIBITM_1B
#undef _RSTM_LIBITM_2B
#undef _RSTM_LIBITM_4B
#undef _RSTM_LIBITM_8B
#undef _RSTM_LIBITM_F
#undef _RSTM_LIBITM_D
#undef _RSTM_LIBITM_LD
#undef _RSTM_LIBITM_CF
#undef _RSTM_LIBITM_CD
#undef _RSTM_LIBITM_CLD
#undef _RSTM_LIBITM_M64
#undef _RSTM_LIBITM_M128
#undef _RSTM_LIBITM_M256

    // ----------------------------------------------------------------------------
    //  memcpy and memmove
    // ----------------------------------------------------------------------------
#define _RSTM_LIBITM_GENERATE_MEM(S, RTxn, WTxn)                        \
    RSTM_LIBITM_DTFN(_ITM_memcpy##S,                                    \
                     ,                                                  \
                     void,                                              \
                     void*, const void*, size_t)                        \
    RSTM_LIBITM_MEMCPY(_ITM_memcpy##S, RTxn, WTxn)                      \
    RSTM_LIBITM_DTFN(_ITM_memmove##S,                                   \
                     ,                                                  \
                     void,                                              \
                     void*, const void*, size_t)                        \
    RSTM_LIBITM_MEMMOVE(_ITM_memmove##S, RTxn, WTxn)

#ifndef RSTM_LIBITM_MEMCPY
# define RSTM_LIBITM_MEMCPY(S, R, W)
# define _RSTM_LIBITM_UNDEF_MEMCPY 1
#endif

#ifndef RSTM_LIBITM_MEMMOVE
# define RSTM_LIBITM_MEMMOVE(S, R, W)
# define _RSTM_LIBITM_UNDEF_MEMMOVE 1
#endif

    _RSTM_LIBITM_GENERATE_MEM(RnWt, false, true)
    _RSTM_LIBITM_GENERATE_MEM(RnWtaR, false, true)
    _RSTM_LIBITM_GENERATE_MEM(RnWtaW, false, true)
    _RSTM_LIBITM_GENERATE_MEM(RtWn, true, false)
    _RSTM_LIBITM_GENERATE_MEM(RtWt, true, true)
    _RSTM_LIBITM_GENERATE_MEM(RtWtaR, true, true)
    _RSTM_LIBITM_GENERATE_MEM(RtWtaW, true, true)
    _RSTM_LIBITM_GENERATE_MEM(RtaRWn, true, false)
    _RSTM_LIBITM_GENERATE_MEM(RtaRWt, true, true)
    _RSTM_LIBITM_GENERATE_MEM(RtaRWtaR, true, true)
    _RSTM_LIBITM_GENERATE_MEM(RtaRWtaW, true, true)
    _RSTM_LIBITM_GENERATE_MEM(RtaWWn, true, false)
    _RSTM_LIBITM_GENERATE_MEM(RtaWWt, true, true)
    _RSTM_LIBITM_GENERATE_MEM(RtaWWtaR, true, true)
    _RSTM_LIBITM_GENERATE_MEM(RtaWWtaW, true, true)

    // Undef RSTM_LIBITM_MEMCPY if we defined it locally.
#ifdef _RSTM_LIBITM_UNDEF_MEMCPY
# undef _RSTM_LIBITM_UNDEF_MEMCPY
# undef RSTM_LIBITM_MEMCPY
#endif

    // Undef RSTM_LIBITM_MEMMOCE if we defined it locally.
#ifdef _RSTM_LIBITM_UNDEF_MEMMOVE
# undef _RSTM_LIBITM_UNDEF_MEMMOVE
# undef RSTM_LIBITM_MEMMOVE
#endif

#undef _RSTM_LIBITM_GENERATE_MEM

    // ----------------------------------------------------------------------------
    //  memset
    // ----------------------------------------------------------------------------
#define _RSTM_LIBITM_GENERATE_MEMSET(S)                          \
    RSTM_LIBITM_DTFN(_ITM_memset##S,                         \
                     ,                                           \
                     void,                                       \
                     void*, int, size_t)                         \
    RSTM_LIBITM_MEMSET(_ITM_memset##S)

#ifndef RSTM_LIBITM_MEMSET
# define RSTM_LIBITM_MEMSET(S)
# define _RSTM_LIBITM_UNDEF_MEMSET 1
#endif

    _RSTM_LIBITM_GENERATE_MEMSET(W)
    _RSTM_LIBITM_GENERATE_MEMSET(WaR)
    _RSTM_LIBITM_GENERATE_MEMSET(WaW)

    // Undef RSTM_LIBITM_MEMSET if we defined it locally.
#ifdef _RSTM_LIBITM_UNDEF_MEMSET
# undef _RSTM_LIBITM_UNDEF_MEMSET
# undef RSTM_LIBITM_MEMSET
#endif

#undef _RSTM_LIBITM_GENERATE_MEMSET

    // Undef RSTM_LIBITM_DTFN if we defined it locally.
#ifdef _RSTM_LIBITM_UNDEF_DTFN
# undef _RSTM_LIBITM_UNDEF_DTFN
# undef RSTM_LIBITM_DTFN
#endif

#ifdef __cplusplus
}
#endif
